DevOps CICD K8s Docker在前一天介紹的Pod、Deployment物件其實是不能在網路上被"直接"存取到的,雖然它們都有各自的IP Address,但這些 IP 僅有在 K8s cluster 內部才有辦法存取的到,若 K8s cluster 要提供對外服務,則需要透過第四層的port-forward,將Pod的Port對應到Node的Port,expose給外部使用者。但若同時有多個 Pods 想要同時被存取時,就需要透過 Service 這個元件。
簡言之:
Service就是K8s提供讓集群內部Pod和集群外世界溝通的一種方式。
可能大家會好奇,為甚麼要有Service的設計?為甚麼不能讓外部直接存取Pod的IP?還要透過Service? 原因有二:
Pod可能很多,例如一個Deployment下的所有Pod,還有之後會介紹的Ingress,Service可以透過 "Selector" 同時選取所有物件,在實務上很方便Pod其實是經常重啟的,一旦Pod重啟,每次的IP都會跟著變動,為了防止每次重啟Pod就要更改一次設定,就需要有個"東西"來幫我們找到重啟後的Pod,這個"東西"就是Service
Service的YAML範例如下:
$ vim svc.yaml
apiVersion: v1
kind: Service
metadata:
name: my-service
spec:
selector:
app: MyApp
ports:
- protocol: TCP
port: 80
targetPort: 9376
創建Service
$ kubectl apply -f svc.yaml
我們看一下其中的欄位設定:
Service 要適用到哪些 Pod,依據label: app=MyApp來選取port-forward的設定,指定Pod的Port對應到的Node的Port,下面會有詳細介紹上述是第一種Service創建方式 (透過YAML),還有第二種創建Service的方法,即透過kubectl expose:
$ kubectl expose po <pod-name> --name=<svc-name> --type=<type-of-svc>
這種方法是將Pod expose給外部使用者,相當於創建一個Service。創建的Service會自動將該Pod的label填入selector欄位,name欄位則輸入Service的名稱,type是Service的類別。
沒錯,
Service是有類別區分的喔,依照不同功能及使用場景,共有三種類別。
Service依照不同功能及使用場景,共有三種Service:NodePort, ClusterIP及LoadBlancer

NodePort的目標是將Pod expose給外部使用者。在Node上開放一個特定Port,再透過Service將port mapping到Pod的Port,如下圖
Node要開放哪個Port,Service會將此Port mapping到Pod的Port上。NodePort範圍是30000 ~ 32767,若NodePort欄位沒有給定,K8s會自動assign一個範圍內的Port為NodePort
Service上的Cluster IP 的Port,此Port會和targetPort 作 mapping。port通常會指定為80
Service可以想像成一個Cluster之中的Virtual Server,這個Virtual Server會擁有自己的IP,這個IP稱為Cluster IP
Pod 上允許外部資源存取的 Port Number,Service會將request forward到這個Port。若在YAML中沒有給定targetPort,則K8s會設定為和port相同的值NodePort的YAML範例如下:
$ vim NP-Svc.yaml
apiVersion: v1
kind: Service
metadata:
name: nodeport-service
spec:
type: NodePort
ports:
- targetPort: 80
port: 80
nodePort: 30008
selector:
app: MyApp

ClusterIP是K8s default的Service Type,它只提供集群內部的服務,集群內的Pod都可以透過它互相訪問,集群外部則無法訪問它
若創建
Service時沒有定義type,K8s會默認為ClusterIP
ClusterIP的應用場景通常是保護某些資料不被外部存取,例如一個Web Application有back-end和front-end,我只想將front-end Pod expose出去,但又想back-end和front-end可以溝通,這時就可以用到ClusterIP Service
ClusterIP的YAML範例如下:
$ vim CIP-Svc.yaml
apiVersion: v1
kind: Service
metadata:
name: clusterip-service
spec:
type: NodePort
ports:
- targetPort: 80
port: 80
selector:
app: MyApp

LoadBalancer 服務expose到 Internet 的標準方式。所有通往指定的Port的流量都會被forward到對應的服務。它沒有過濾條件,沒有路由等。也就是說,你可以發送任何種類的流量到該服務,像 HTTP,TCP,UDP,Websocket,gRPC 或其它種類。這個方式的最大缺點是每一個用 LoadBalancer 暴露的服務都會有它自己的 IP ,每個用到的 LoadBalancer 都需要付費,所以LoadBalancer通常會和Ingress一起使用。
因為
LoadBalancer通常會和Ingress一起使用,而Ingress又比較複雜,有機會的話之後再介紹
事實上,
Service不是存在於任一Node的物件,它是屬於Cluster based的resource-object,因此當Service在select Pod時,才可以選到其他Node的Pod
今天介紹了Service這個物件,因為Service內容比較多,如果不拉一天介紹的話感覺不太能銜接後面會遇到的題目,所以特別介紹一下。好啦,今天就到這囉~ 謝謝大家~
Service
Kubernetes - Services Explained in 15 Minutes!
[Kubernetes] How to Implement Kubernetes Service - ClusterIP
KubernetesService Overview
You can find me on